package com.group.transaction.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.group.transaction.domain.*;
import com.group.transaction.enums.IntegralLogTypeEmun;
import com.group.transaction.exception.SystemException;
import com.group.transaction.hander.ServiceDataHandler;
import com.group.transaction.mapper.*;
import com.group.transaction.model.FrequentLoginError;
import com.group.transaction.model.ResultJson;
import com.group.transaction.model.SmsCode;
import com.group.transaction.service.user.UserSrevice;
import com.group.transaction.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author YunXing Pang
 * @date 2020/3/15
 */
@Service
@Slf4j
public class UserSreviceImpl implements UserSrevice {

    /**
     * 频繁登录失败的map集合
     */
    private static final ConcurrentHashMap<String, FrequentLoginError> FREQUENT_LOGIN_ERROR_MAP = new ConcurrentHashMap<>(16);

    /**
     * 短信验证码
     */
    private static final ConcurrentHashMap<String, SmsCode> SMS_CODE = new ConcurrentHashMap<>(16);

    /**
     * 注册锁
     */
    private static final ReentrantLock REGISTER_LOCK = new ReentrantLock(true);

    @Resource
    private UserMapper userMapper;

    @Resource
    private IntegralMapper integralMapper;

    @Resource
    private UserCodeMapper userDeletedCodeMapper;

    @Resource
    private IntegralLogMapper integralLogMapper;

    @Resource
    private ServiceDataHandler serviceDataHandler;

    @Resource
    private UserAddressMapper userAddressMapper;

    @Resource
    private OperationLogMapper operationLogMapper;

    @Override
    public User selectUserByUsernameOrPhone(String data) {
        return userMapper.selectUserByUsernameOrPhone(data);
    }

    @Override
    public ResultJson login(User user) {
        FrequentLoginError frequentLogin = FREQUENT_LOGIN_ERROR_MAP.get(user.getUsername());
        long dateTime = System.currentTimeMillis();
        if (Objects.nonNull(frequentLogin) && frequentLogin.getErrorCount() > 2 && dateTime - frequentLogin.getDateTime() < 3600 * 1000) {
            return ResultJson.builder().code(0).message("登录失败已达3次，请1个小时后再试").build();
        }

        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(usernamePasswordToken);
        } catch (Exception e) {
            log.error("登录出现异常：{}", e);
            return ResultJson.builder().code(0).message("登录失败，用户名或密码错误").build();
        }
        if (!subject.isAuthenticated()) {
            log.error("登录失败，用户名或密码错误");

            if (Objects.isNull(frequentLogin)) {
                frequentLogin = new FrequentLoginError();
            }
            frequentLogin.setErrorCount(frequentLogin.getErrorCount() + 1);
            frequentLogin.setDateTime(dateTime);
            FREQUENT_LOGIN_ERROR_MAP.put(user.getUsername(), frequentLogin);

            return ResultJson.builder().code(0).message("登录失败").build();
        }

        FREQUENT_LOGIN_ERROR_MAP.remove(user.getUsername());

        user = (User) subject.getPrincipal();
        log.info("登录成功，获取到数据：{}", JSON.toJSONString(user));
        Session session = subject.getSession();
        session.setAttribute("user", user);
        return ResultJson.builder().code(1).message("登录成功").result(user.getType()).build();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ResultJson register(User user) {
        REGISTER_LOCK.lock();
        try {
            boolean isRegister = Objects.nonNull(userMapper.selectUserByPhone(user.getPhone()));
            if (isRegister) {
                log.error("该用户名或者手机号已被使用，用户名：{}", user.getUsername());
                return ResultJson.builder().code(0).message("该用户名或者手机号已被注册").build();
            }

            /*
              验证短信验证码
             */
            SmsCode smsCode = SMS_CODE.get(user.getPhone());
            if(smsCode == null) {
                return ResultJson.builder().code(0).message("该验证码输入错误，请重新输入或者获取").build();
            }
            boolean timeOut = System.currentTimeMillis() - smsCode.getCreateTime() > 5 * 60 * 1000;
            if (timeOut) {
                SMS_CODE.remove(user.getPhone());
                log.error("该短信验证码已失效，短信验证码：{}", user.getSmsCode());
                return ResultJson.builder().code(0).message("该短信验证码已失效，请重新输入或者获取").build();
            } else if (!Objects.equals(smsCode.getSmsCode(), user.getSmsCode())) {
                log.error("该短信验证码错误，短信验证码：{}", user.getSmsCode());
                return ResultJson.builder().code(0).message("该短信验证码错误，请重新输入或者获取").build();
            }
            SMS_CODE.remove(user.getPhone());

            /*
             判断是否有邀请人并给邀请人加积分
             */
            if(user.getCode() != null) {
                // 计算 邀请人 获取的 积分
                User oldUser = userMapper.findCodeOrderByIdDesc(user.getCode());
                if(oldUser != null) {
                    calculatePointsByInviter(user);
                }else {
                    return ResultJson.builder().code(0).message("该邀请码错误，请重新输入").build();
                }
            }


            // 生成邀请码
            String code = generateInvitationCode();

            String salt = StringUtil.getUUID();
            user.setSalt(salt);
            user.setPassword(new Md5Hash(user.getPassword(), salt, 2).toString());
            user.setCode(code);
            int success = userMapper.insert(user);
            if (success == 0) {
                throw new SystemException("注册失败！");
            }

            // 计算 用户注册 获取的 积分
            calculatePointsByUserRegister(user.getId());
            OperationLog operationLog = new OperationLog();
            operationLog.setContent("新增用户："+ user.getShowName());
            operationLog.setType(1);
            operationLog.setTime(new Date());
            operationLogMapper.insert(operationLog);
            return ResultJson.builder().code(1).message("注册成功").build();
        } finally {
            REGISTER_LOCK.unlock();
        }
    }

    /**
     * 计算 用户注册 获取的 积分
     *
     * @param userId 用户id
     */
    private void calculatePointsByUserRegister(Long userId) {
        int success;
        Integral integral = serviceDataHandler.calculatePoints(userId, 60.0);
        success = integralMapper.insert(integral);
        if (success == 0) {
            throw new SystemException("注册失败！");
        }
        IntegralLog integralLog = IntegralLog.builder().type(IntegralLogTypeEmun.REGISTER.getType()).userId(userId).content("注册赠送积分")
                .time(new Date()).integral("+"+ 60.0).build();
        success = integralLogMapper.insertSelective(integralLog);
        if (success == 0) {
            throw new SystemException("注册失败！");
        }
    }

    /**
     * 生成邀请码
     *
     * @return 邀请码
     */
    private String generateInvitationCode() {
        String code;
        UserCode userDeletedCode = userDeletedCodeMapper.findFirst();
        if (Objects.nonNull(userDeletedCode)) {
            code = userDeletedCode.getCode();
            int success = userDeletedCodeMapper.delete(userDeletedCode);
            if (success == 0) {
                throw new SystemException("注册失败！");
            }
        } else {
            code = userMapper.findCodeOrderByIdDesc(null).getCode();
            if (StringUtil.isEmpty(code)) {
                code = "100000";
            } else {
                code = String.valueOf(NumberUtils.toInt(code) + 1);
            }
        }
        return code;
    }

    /**
     * 计算 邀请人 获取的 积分
     *
     * @param
     */
    private void calculatePointsByInviter(User user) {
        String oldCode = user.getCode();
        if (StringUtil.isNotEmpty(oldCode)) {
            User oldUser = userMapper.findCodeOrderByIdDesc(oldCode);
            user.setUserId(oldUser.getId());
            Integral integral = serviceDataHandler.calculatePoints(oldUser.getId(), 15.0);
            int success = integralMapper.updateByPrimaryKeySelective(integral);
            if (success == 0) {
                throw new SystemException("注册失败！");
            }
            IntegralLog integralLog = IntegralLog.builder().type(IntegralLogTypeEmun.INVITE.getType()).userId(oldUser.getId()).content("邀请赠送积分")
                    .integral("+"+ 15.0).time(new Date()).build();
            success = integralLogMapper.insertSelective(integralLog);
            if (success == 0) {
                throw new SystemException("注册失败！");
            }
        }
    }

    @Override
    public ResultJson sendSmsCode(String phone) {
        Random random = new Random();
        String smsCode = String.valueOf(random.nextInt(999999)%(999999-100000+1) + 100000);
        SMS_CODE.put(phone, SmsCode.builder().smsCode(smsCode).createTime(System.currentTimeMillis()).build());
        serviceDataHandler.sendSms(phone,  smsCode );
        return ResultJson.builder().code(1).message("发送成功").build();
    }



    /**
     * 编辑用户
     *
     * @param user
     * @return
     */
    @Override
    @Transactional
    public ResultJson compileUser(User user) {
        if(user.getPassword() != null) {
            if("原始密码123".equals(user.getPassword())) {
                user.setPassword("");
            }else {
                String salt = StringUtil.getUUID();
                user.setSalt(salt);
                user.setPassword(new Md5Hash(user.getPassword(), salt, 2).toString());
            }

        }
        int num = userMapper.updateByPrimaryKeySelective(user);
        if(num == 1) {
            User loginUser = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
            OperationLog operationLog = new OperationLog();
            operationLog.setContent(loginUser.getShowName() != null ? loginUser.getShowName() : "--"  +"编辑了【"+ user.getShowName() != null ? user.getShowName()
                    : "--"+"】");
            operationLog.setType(2);
            operationLog.setTime(new Date());
            operationLogMapper.insert(operationLog);
            return ResultJson.builder().code(1).message("编辑成功").build();
        }else {
            return ResultJson.builder().code(-1).message("编辑失败").build();
        }
    }

    /**
     * 删除用户
     *
     * @param user
     * @return
     */
    @Override
    @Transactional
    public JSONObject deleteUser(User user) {

        User loginUser = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        int num = userMapper.deleteByPrimaryKey(user);
        if(num == 1) {
            OperationLog operationLog = new OperationLog();
            operationLog.setContent(loginUser.getShowName() != null ? loginUser.getShowName() : "--"  +"删除了【"+ user.getShowName() != null ? user.getShowName()
                    : "--"+"】");
            operationLog.setType(3);
            operationLog.setTime(new Date());
            operationLogMapper.insert(operationLog);
        }
        return new JSONObject().fluentPut("result", num);
    }

    /**
     * 查询用户
     *
     * @param user
     * @return
     */
    @Override
    public JSONObject queryUserData(User user) {
        List<User> userList = userMapper.queryUserData(user);
        Integer total = userMapper.queryUserDataTotal(user);
        return new JSONObject().fluentPut("result", userList).fluentPut("total", total);
    }
    /**
     * 查询当前用户宴请码
     * @param
     * @return
     */
    @Override
    public JSONObject queryUserCode() {
        User user = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        return new JSONObject().fluentPut("result", userMapper.queryUserCode(user.getId()));
    }
    /**
     * 通过用户ID查询用户地址
     * @return
     */
    @Override
    public JSONObject queryUserAddressByUserId() {
        User user = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        List<UserAddress> userAddressList = userAddressMapper.queryUserAddressByUserId(user.getId());
        return new JSONObject().fluentPut("result",userAddressList).fluentPut("phone",user.getPhone());
    }
    /**
     * 新增发货地址
     */
    @Override
    public ResultJson addSendAddress(String address) {
        User user = (User) SecurityUtils.getSubject().getSession().getAttribute("user");
        UserAddress userAddress = new UserAddress();
        userAddress.setUserId(user.getId());
        userAddress.setAddress(address);
        int num = userAddressMapper.insert(userAddress);
        if(num < 0) {
            return ResultJson.builder().code(-1).message("添加失败").build();
        }else {
            return ResultJson.builder().code(1).message("添加成功").build();
        }

    }
    /**
     * 根据用户ID查询用户信息
     */
    @Override
    public ResultJson queryUserDataByUserId(Long userId){
        return ResultJson.builder().code(1).message("成功").result(userMapper.queryUserDataByUserId(userId)).build();
    }
    /**
     * 手机号码和身份证后四位寄件
     */
    @Override
    public ResultJson sendLogistics(User user) {
        User data = userMapper.sendLogistics(user);
        if(data != null) {
            return ResultJson.builder().code(1).message("成功").result(data).build();
        }else {
            return ResultJson.builder().code(-1).message("获取数据失败").build();
        }

    }
    /**
     * 通过用户ID查询用户地址
     * @return
     */
    @Override
    public ResultJson queryAddressByUserId(String userId) {
        if(userId != null && !"".equals(userId)) {
            User user = new User();
            user.setId(Long.parseLong(userId));
            List<UserAddress> userAddressList = userAddressMapper.queryUserAddressByUserId(user.getId());
            return ResultJson.builder().code(1).message("成功").result(userAddressList).build();
        }else {
            return ResultJson.builder().code(-1).message("获取数据失败").build();
        }
    }
    /**
     * 新增发货地址
     */
    @Override
    public ResultJson addUserAddress(User user) {
        UserAddress userAddress = new UserAddress();
        userAddress.setUserId(user.getId());
        userAddress.setAddress(user.getAddress());
        int num = userAddressMapper.insert(userAddress);
        if(num < 0) {
            return ResultJson.builder().code(-1).message("添加失败").build();
        }else {
            return ResultJson.builder().code(1).message("添加成功").build();
        }

    }

}
